package com.lu.core.support;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lu.core.annotations.DataScope;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.GroupByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;

import java.lang.reflect.Method;

/**
 * @program lu-boot-saas
 * @description: 数据范围权限 抽象层
 * @author: zhanglu
 * @create: 2022-09-27 16:41:00
 */
public abstract class DataScopePermissionAbstract {

    public void setSqlSegment(PlainSelect plainSelect, String mappedStatementId) {
        try {
            DataScopeProxy.DataScope dataScope = DataScopeProxy.DATA_SCOPE_EXECUTE.get();
            if(dataScope == null){
                this.annotationExecute(plainSelect, mappedStatementId);
            }else {
                if(!ObjectUtil.isAllNotEmpty(dataScope.getName(), dataScope.getHandler())){
                    return;
                }
                Expression mark = this.getExpression();
                if(mark == null){
                    return;
                }
                this.methodExecute(dataScope, plainSelect, mark);
            }
        } finally {
            DataScopeProxy.DATA_SCOPE_EXECUTE.remove();
        }
    }

    private void annotationExecute(PlainSelect plainSelect, String mappedStatementId) {
        Expression mark = null;
        String classPath = mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."));
        String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
        Class<?> clazz = null;
        try {
            clazz = Class.forName(classPath);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if(!method.getName().equalsIgnoreCase(methodName)){
                continue;
            }
            DataScope annotation = method.getAnnotation(DataScope.class);
            if(annotation == null){
                continue;
            }
            if(!annotation.handler().getName().equalsIgnoreCase(this.getClass().getName())){
                continue;
            }
            mark = this.getExpression();
            if(mark == null){
                return;
            }
            DataScopeProxy.DataScope dataScope = DataScopeProxy.DataScope.builder()
                    .name(annotation.name()).groupBy(annotation.groupBy())
                    .handler(annotation.handler()).build();
            this.methodExecute(dataScope, plainSelect, mark);
        }
    }

    protected void methodExecute(DataScopeProxy.DataScope dataScope, PlainSelect plainSelect, Expression mark){
        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(new Column(dataScope.getName()));
        equalsTo.setRightExpression(mark);
        if (null == plainSelect.getWhere()) {
            // 不存在 where 条件
            plainSelect.setWhere(new Parenthesis(equalsTo));
        } else {
            // 存在 where 条件 and 处理
            // 创建 AND 表达式 拼接Where 和 = 表达式
            plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), equalsTo));
        }
        if(ObjectUtil.isNotEmpty(dataScope.getGroupBy())){
            GroupByElement groupByElement = new GroupByElement();
            for (String column : dataScope.getGroupBy().split(StrUtil.COMMA)) {
                groupByElement.addGroupByExpressions(new Column(column));
            }
            plainSelect.setGroupByElement(groupByElement);
        }
    }

    protected abstract Expression getExpression();

}
